
var roomCounts = 40;
var combineLevels = [20, 45];

function getCombineLevel(userLevel){
    for( var i=0,max=combineLevels.length; i<max; i++ ) {
        if( combineLevels[i] > userLevel ) {
            break;
        }
    }

    if( i<=0 ) {
        return 0;
    }

    return combineLevels[i-1];
}

function sortNumber(a, b) {
    return b.fightForce - a.fightForce;
}

function getFightRids(roles) {
    var retRids = [];    
    var rolesArr = [];
    for( var rid in roles ) {
        rolesArr.push({id : +rid, fightForce : roles[rid]});
    }
    
    // 从大到小排序
    rolesArr.sort(sortNumber);
    for( var i = 0; i < 3; i++) {
        retRids.push(rolesArr[i].id);
    }    

    return retRids;
};

function Combine(){
    this.combines = {};
    this.leaves = {};/* {uid :{award: robbed : lost:}}
                    */
    this.updates = {};
}

Combine.create = function() {
    var initCombine = {};
    // 初始化合璧,等级-房间编号
    for( var i = 0, max = combineLevels.length; i < max; i++ ) {
        var level = combineLevels[i];
        initCombine[level] = {};
        for( var id = 1; id <= roomCounts; id++ ) {
            initCombine[level][id] = {
                'country' : '',     // 房间所属国家
                'timer' : 0,        // 合璧开始的时间
                'left':{            // 房间左边位置
                    'uid' : 0,      // 玩家uid
                    'stone' :0,     // 玩家拥有的半块玉璧ID
                },
                'right':{           // 房间右边位置
                    'uid':0,        // 玩家uid
                    'stone':0,      // 玩家拥有的半块玉璧ID
                },
            }; 
        }
         
    }
        
    gDBWorld.insert({_id:'combine', combine:initCombine}, function(err, result){}); 
};

Combine.prototype = {
    init : function(callback) {

        gDBWorld.findOne({_id : 'combine'}, {}, function(err, doc){
            if( doc ) {
                this.combines = doc.combine;
                callback && callback(true);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    markCombineDirty : function(level, id, room){
        this.updates[['combine',level, id].join('.')] = room;
    },

    save : function(callback) {
        if( !this.updates || Object.keys(this.updates).length == 0 ) {
            callback && callback(true);
            return;
        }

        var updates = this.updates;
        gDBWorld.update({_id : 'combine'}, {$set:updates}, function(err, result){
            if( err ) {
                ERROR({updates:updates, err:err});
                callback && callback(false);
            }else {
                callback && callback(true);
            }
        });

        this.updates = {};
    },

    saveLeave : function(uid) {
        var leave = this.leaves[uid] || 0;
        gDBWorld.save({_id:'combine_leave_'+uid, 'leave':leave}, function(err, result){});
    },

    getLeave : function(uid, callback) {
        if( uid in this.leaves ) {
            callback(this.leaves[uid]);
        }else {
            gDBWorld.findOne({_id : 'combine_leave_'+uid}, {}, function(err, doc){
                var leave = doc ? doc.leave : 0; 
                this.leaves[uid] = leave;
                callback && callback(this.leaves[uid]);
            }.bind(this));
        }
    },

    update : function(level) {
        var now = common.getTime();
        var maxTime = gConfGlobal.CombineTimerLimit;
        var combines = this.combines[level];
        for( var id in combines ) {
            var room = combines[id];
            if( !room.timer || (room.timer+maxTime) > now ) {
                continue;
            }
    
            var stone = (room.left.stone > room.right.stone) ?  room.left.stone : room.right.stone; 
            this.leaves[room.left.uid] = {award:stone, robbed :0, lost:0};
            this.leaves[room.right.uid] = {award:stone, robbed :0, lost:0};
            this.saveLeave(room.left.uid);
            this.saveLeave(room.right.uid);
            room.country = '';
            room.timer = 0;
            room.left.uid = 0;
            room.left.stone = 0;
            room.right.uid = 0;
            room.right.stone = 0;

            this.markCombineDirty( level, id, room );
        }
    },

    getCombineByPage : function(combine, page) {
        page = parseInt(page)*4;
        var ids = [page-3,page-2,page-1,page];
        var retCombine = {};
        for( var i = 0, max = ids.length; i < max; i++) {
            var id = ids[i];
            var room = combine[id];
            retCombine[id] = {
                'country':room.country, 
                'timer':room.timer,
                'left':{}, 
                'right':{},
            };

            var sides = ['left', 'right'];
            for( var j = 0; j < 2; j++) {
                var side = sides[j];
                var user = room[side];
                var uid = user.uid;
                if( !uid ) {
                    retCombine[id][side] = {
                        'uid' : 0,
                        'stone': 0,
                        'name':'',
                        'headpic':'',
                    }
                }else {
                    var userInfo = gUserInfo.getUser(uid);
                    retCombine[id][side] = {
                        'uid' : uid,
                        'stone': user.stone,
                        'name':userInfo.name,
                        'headpic':userInfo.headpic,
                    }
                }
            }
        }

        return retCombine;
    },
};

exports.get_stone = function(req, resp, onHandled) {
    do {
        var weights = {};
        for( var id in gConfCombine ) {
            weights[id] = gConfCombine[id].Rate; 
        }   

        resp.data.stone = +common.wRand(weights); 

    }while (false);    

    onHandled();
}

exports.get = function(req, resp, onHandled) {

    gCombine.getLeave(req.uid, function(leave) {
        do{
            var uid = +req.uid; 
            if( !( uid in gLeague.leagues[req.args.league_name].members) ) {
                resp.data.fired = 1; 
                break;
            }

            var occupying = req.args.occupying;
            var page = parseInt(req.args.page);
            var userLevel = req.args.level;
            
            var level = getCombineLevel(userLevel);
            var matchLevel = level;
            if( occupying && !leave ) {
                level = +occupying.level; 
            }else if( !occupying && leave ) {
                gCombine.leaves[uid] = 0; 
                gCombine.saveLeave(uid);
            }

            gCombine.update(level);

            leave = gCombine.leaves[uid]; 
            if( !leave ) {
                if( occupying ) {
                    var combineData = gCombine.combines[occupying.level][occupying.id];
                    if( combineData.left.uid != uid && combineData.right.uid != uid ) {
                        resp.data.robbed = 1;
                    }
                }
                resp.data.combines = gCombine.getCombineByPage(gCombine.combines[level], page); 
            }else {
                if( leave.award ) {
                    var gems = null;
                    if( userLevel < 45 ) {
                        gems = gConfCombine[leave.award].Gem1; 
                    }else {
                        gems = gConfCombine[leave.award].Gem2; 
                    }
                    
                    resp.data.awards = [['gem',common.randArray(gems),1]];
                }else if( leave.robbed ) {
                    resp.data.robbed = leave.robbed; 
                    resp.data.lost = leave.lost;
                }  
                
                gCombine.leaves[uid] = 0;
                gCombine.saveLeave(uid);

                resp.data.combines = gCombine.getCombineByPage(gCombine.combines[matchLevel], page); 
            }
            
        }while(false);
        
        if( resp.code != 0 ) {
            onHandled();
            return;
        }

        gCombine.save();
        onHandled();
    });
}

exports.rob = function(req, resp, onHandled) {

    var uid = req.uid;
    var leagueName = req.args.league_name;
    if( !( uid in gLeague.leagues[leagueName].members) ) {
        resp.data.fired = 1; 
        onHandled();
        return;   
    }

    var atkFightForce = req.args.fight_forces; 
    var level = getCombineLevel(req.args.level);
    var id = parseInt(req.args.id); 
    var side = req.args.side;
    var room = gCombine.combines[level][id];

    // 是否正在合璧
    var isCombining = false;
    // 选出被抢夺一方最强的一个玩家
    var defUid = 0;
    do {
        if( !room[side].uid ) {
            resp.data.update = 1; 
            resp.data.combines = gCombine.getCombineByPage(gCombine.combines[level], ((id-1)/4 + 1) ); 
            break;
        }

        if( room.country == gLeague.leagues[leagueName].country ) {
            resp.code = 1;  resp.desc = 'same country '; break;
        }
        
        if( !room.timer ) {
            defUid = room[side].uid; 
        }else {
            var leftUserInfo = gUserInfo.getUser(room.left.uid);    
            var rightUserInfo = gUserInfo.getUser(room.right.uid);
            if( leftUserInfo.fight_force >= rightUserInfo.fight_force ) {
                defUid = room.left.uid; 
            }else {
                defUid = room.right.uid; 
            }

            isCombining = true;
        }
        
    }while(false);
    
    if( 1==resp.code || 1 == resp.data.update ) {
        onHandled();
        return;
    }

    // 参与防守战斗的那个玩家
    gPlayers.get(defUid, function(defender){
        do {
            if( !defender ) {
                resp.code = 1; resp.desc = 'player.init'; break;
            }
            
            var defInfo = defender.user.role;
            if( Object.keys(defender.user.role).length < 3 ) {
                resp.code = 1;  resp.desc = 'at least 3 roles'; break;
            }
            
            var roles = defender.user.role;
            var defRoles = {};
            for( var rid in roles ) {
                var role = roles[rid];
                defender.calculateRoleAttr(role);
                defRoles[rid] = role.fight_force;
            }

            var defRids = getFightRids(defRoles);
            var defFightForce = [defRoles[defRids[0]], defRoles[defRids[1]], defRoles[defRids[2]] ];
   
            var result = [0, 0, 0];
            for( var i = 0; i < atkFightForce.length; i++ ){
                var diffFightForce = atkFightForce[i] - defFightForce[i]; 

                var win = 0;
                if( 0 == diffFightForce ){
                    win = common.randRange(0, 1);
                }else{
                    win = diffFightForce > 0 ? 1 : 0;
                }

                result[i] = win;
            }
            
            // 被抢璧的那个玩家
            var robbedUser = room[side];
            var robbedUid = robbedUser.uid;
            var robbedLost = 0;

            // 另一个合璧的玩家 
            var anotherUid = 0;

            var succ = (result.sum() > 1) ? true : false; 
            if( succ ) {
                gCombine.leaves[robbedUid] = {award :0, robbed :1, lost:1};             
                robbedLost = 1;
                gCombine.saveLeave(robbedUid);
                if( isCombining ) {
                    var anotherSide = 'left';
                    if( anotherSide == side ) {
                        anotherSide = 'right';
                    }
                     
                    anotherUid = room[anotherSide].uid;
                    gCombine.leaves[anotherUid] = {award :0, robbed :1, lost:0};             
                    gCombine.saveLeave(anotherUid);
                }
                
                resp.data.stone = room[side].stone;

                room.country = '';
                room.timer = 0;
                room.left.uid = 0;
                room.left.stone = 0;
                room.right.uid = 0;
                room.right.stone = 0;

                gCombine.markCombineDirty(level, id, room); 
            }        
   
            var userInfo = gUserInfo.getUser(uid);
            var now = common.getTime();
            // 给被抢璧的玩家
            var message = {
                'uid' : uid, 
                'name': userInfo.name,
                'time': now,
                'succ': succ,
                'lost': robbedLost,
                'type': 'combine',
            };
            
            gMessage.addMessage(robbedUid, message); 
            // 给另一个合璧的玩家
            if( isCombining ) {
                var message = {
                    'uid' : uid, 
                    'name': userInfo.name, 
                    'time': now,
                    'succ': succ,
                    'lost': 0,
                    'type': 'combine',
                };
                
                gMessage.addMessage(anotherUid, message); 
            }

            resp.data.roles = defRids;
            resp.data.result = result;

        } while(false);
        
        gCombine.save();
        onHandled();
    });
}

exports.join = function(req, resp, onHandled) {
    do {
        var uid = req.uid;
        var leagueName = req.args.league_name;
        if( !( uid in gLeague.leagues[leagueName].members) ) {
            resp.data.fired = 1; 
            break;
        }
        
        var userInfo = gUserInfo.getUser(uid);
        var id = parseInt(req.args.id); 
        var level = getCombineLevel(req.args.level);
        var stone = req.args.stone;
        var side = gConfCombine[stone].Side;
        var room = gCombine.combines[level][id];
        var userCountry = gLeague.leagues[leagueName].country;
        if( room[side].uid ) {
            resp.data.update = 1; 
            resp.data.combines = gCombine.getCombineByPage(gCombine.combines[level], ((id-1)/4 + 1) ); 
            break;
        }

        if( room.country && room.country != userCountry ) {
            resp.code = 1; resp.desc = 'different country'; break;
        }

        if( !room.country ) {
            room.country = userCountry; 
        }else {
            room.timer = common.getTime();
        }

        room[side].uid = uid; 
        room[side].stone = stone; 

        gCombine.markCombineDirty(level,id,room);
        resp.data.level = level;

    }while(false);

    gCombine.save();
    onHandled();
}

exports.leave = function(req, resp, onHandled) {
    do {
        var uid = req.uid;
        var occupying = req.args.occupying;
        var stone = req.args.stone;
        var level = occupying.level;
        var id = occupying.id;
         
        var room = gCombine.combines[level][id];
        var side = gConfCombine[stone].Side;
        if( room[side].uid != uid ) {
            resp.data.update = 1; 
            resp.data.robbed = 1;
            break;
        }

        if( room.timer ) {
            resp.data.update = 1; 
            break;
        }

        room.country = '';
        room[side].stone = 0; 
        room[side].uid = 0;

        gCombine.markCombineDirty(level, id, room);

    }while(false);

    if( 1==resp.data.update ) {
        resp.data.combines = gCombine.getCombineByPage(gCombine.combines[level], ((id-1)/4 + 1) ); 
    }

    gCombine.save();
    onHandled();
}

exports.Combine = Combine;
